'''
Created on Jun 13, 2010

@author: oabalbin


'''

import operator
from operator import itemgetter
from collections import deque, defaultdict


# my libraries
import interactome.databases.query as iq
#from interactome.databases.DBs import ucsc, STRING
from interactome.common.classes import interaction

class myInteractome:
    def __init__(self):
        Udbhost, Udbuser, Udbpasswd, Udatabase = "localhost", "alejo", "oscar", "ucsc_tables"
        self.ucsc = iq.query(Udbhost, Udbuser, Udbpasswd, Udatabase)
        
        Sdbhost, Sdbuser, Sdbpasswd, Sdatabase = "localhost", "alejo", "oscar", "STRING8"
        self.STRING = iq.query(Sdbhost, Sdbuser, Sdbpasswd, Sdatabase)

        
    def get_proteins_in_network(self,list_of_genes=[]):
        """
        Extracts a protein interaction network from the string database
        If not genelist is passed, then it uses all known genes in ucsc
        Returns a dictionary {gen:protein} and a list of not found genes
        """
    
        if not list_of_genes:
            list_of_genes = self.ucsc.get_all_knownGenes_from_ucsc()
            
        list_of_proteins, list_of_proteins_reverseIndex, genes_notfound, prot2gene_table = self.STRING.map_genes2proteins_in_string(list_of_genes)
        return list_of_proteins, list_of_proteins_reverseIndex, genes_notfound, prot2gene_table
        
            
    def get_interactions_in_network(self,list_of_proteins,trans2prot_edge=False):
        """
        This function extract the interaction between proteins from the STRING database
        It scores each interaction according to the cummulative string score
        Interactions with particular scores can be selected.
        Returns list of objects interaction-object.
        """
        
        #list_of_interactions = self.STRING.extract_protein_interactions(list_of_proteins) # old query in string
        list_of_interactions = self.STRING.extract_protein_interactions_string8(list_of_proteins,trans2prot_edge)
        ######selection of the interactions according to score 
            
        return list_of_interactions
    
    
    def select_interactions_by_score(self, list_of_interactions, score_value=[]):
        """
        Default score - value: combinedscore - 500
        Returns a selected list of interactions according to the pair score - value
        """
        selected_nodes = set()
        selected_interactions = deque()
        
        if not score_value:
            score = 'combined_score'
            threshold_value = 500
            sorted_list_interactions = sorted(list_of_interactions, key=operator.attrgetter(score), reverse=True)
        else:
            score = score_value[0]
            threshold_value = score_value[1]
            sorted_list_interactions = sorted(list_of_interactions, key=operator.attrgetter(score), reverse=True)
        
        f = operator.attrgetter(score)
        for thisIntc in sorted_list_interactions:
            myscore_value = f(thisIntc)
            
            if myscore_value < threshold_value:
                break
            else:
                # Add the mode of the interaction between item_a and item_b
                interaction_mode = self.STRING.extract_protein_interaction_mode(thisIntc.item_id_a, thisIntc.item_id_b)
                thisIntc.update_mode_action(interaction_mode[0],interaction_mode[1], interaction_mode[2])
                
                selected_interactions.append(thisIntc)
                selected_nodes.add(thisIntc.item_id_a)
                selected_nodes.add(thisIntc.item_id_b)
                        
        return selected_interactions, list(selected_nodes)
        
    def select_interactions_by_scoreS8(self, list_of_interactions, score_value=[]):
        """
        Default score - value: combinedscore - 500
        Returns a selected list of interactions according to the pair score - value
        """
        selected_nodes = set()
        selected_interactions = deque()
        
        if not score_value:
            score = 'combined_score'
            threshold_value = 500
            sorted_list_interactions = sorted(list_of_interactions, key=operator.attrgetter(score), reverse=True)
        else:
            score = score_value[0]
            threshold_value = score_value[1]
            sorted_list_interactions = sorted(list_of_interactions, key=operator.attrgetter(score), reverse=True)
        
        f = operator.attrgetter(score)
        for thisIntc in sorted_list_interactions:
            myscore_value = f(thisIntc)
            
            if myscore_value < threshold_value:
                break
            else:
                # Add the mode of the interaction between item_a and item_b
                interaction_mode = self.STRING.extract_protein_interaction_mode(thisIntc.item_id_a, thisIntc.item_id_b)
                thisIntc.update_mode_action(interaction_mode[0],interaction_mode[1], interaction_mode[2])
                
                selected_interactions.append(thisIntc)
                selected_nodes.add(thisIntc.item_id_a_hugo)
                selected_nodes.add(thisIntc.item_id_b_hugo)
                        
        return selected_interactions, list(selected_nodes)

        


"""
f = attrgetter('name'), the call f(b)
        
myInt = myInteractome()
list_of_proteins, list_of_proteins_revIndex, notfound = myInt.get_proteins_in_network()
print len(list_of_proteins)
list_of_interactions = myInt.get_interactions_in_network(list_of_proteins.values())
print len(list_of_interactions)
selected_interactions, selected_nodes = myInt.select_interactionsByscore(list_of_interactions)
print len(selected_interactions)
"""

